package org.serverct.finalfight.internal.game.basic;

import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;
import org.bukkit.scoreboard.Scoreboard;
import org.serverct.finalfight.FinalFight;
import org.serverct.finalfight.game.gui.PersistentInventory;
import org.serverct.finalfight.game.gui.SpectatorTeleporter;
import org.serverct.finalfight.game.hadesgame.EventHandler;
import org.serverct.finalfight.internal.game.hadesgame.BasicEvent;
import org.serverct.finalfight.internal.info.ScoreBoardHandler;
import org.serverct.finalfight.internal.info.SimpleInfoHandler;
import org.serverct.finalfight.stat.StatManager;
import org.serverct.finalfight.util.CustomSettings;
import org.serverct.finalfight.util.StringPair;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;

public abstract class BasicGame {
    public int min;
    public int max;
    public int timeCounter;
    public String id;
    public WorldManager worldManager;
    public GameState state;
    public GameType type;
    public HashMap<UUID, BasicGamer> players;

    public boolean enableRandomEvents;
    public int nextevent_sec;
    public BasicEvent currentevent;

    private final BasicGame game;
    private BukkitTask downing = null;

    public BasicGame(YamlConfiguration yaml) {
        this.id = yaml.getString("id");
        this.min = yaml.getInt("min");
        this.max = yaml.getInt("max");
        this.timeCounter = 0;
        this.worldManager = new WorldManager(yaml);
        this.state = GameState.WAITING;
        this.players = new HashMap<>();
        this.enableRandomEvents = yaml.getBoolean("enablerandomevents");
        if (this.enableRandomEvents) {
            this.nextevent_sec = CustomSettings.config.getInt("period");
            this.currentevent = null;
        }
        this.game = this;
        new BukkitRunnable() {
            @Override
            public void run() {
                EventHandler.executeRandomEvents(game);
                ScoreBoardHandler.sendScoreBoard(game);
            }
        }.runTaskLater(FinalFight.plugin, 1L);
    }

    public void join(Player player,boolean isSpectator) {
        UUID uuid = player.getUniqueId();
        if (this.players.containsKey(uuid)) {
            SimpleInfoHandler.sendMessage(player, true, "alreadyin");
            return;
        }
        if (this.state == GameState.RUNNING) {
            SimpleInfoHandler.sendMessage(player, true, "alreadystarted");
            return;
        }
        if (this.state == GameState.REFRESHING) {
            SimpleInfoHandler.sendMessage(player, true, "refreshing");
            return;
        }
        if (this.players.size() >= this.max && !isSpectator) {
            SimpleInfoHandler.sendMessage(player, true, "full");
            return;
        }
        this.players.put(uuid, new BasicGamer(!isSpectator));

        PersistentInventory.saveInventory(player);
        PersistentInventory.clearInventory(player);
        player.teleport(this.worldManager.hub);
        player.setGameMode(GameMode.SURVIVAL);
        if(isSpectator)
            player.getInventory().setItem(4,SpectatorTeleporter.menuItem.clone());

        SimpleInfoHandler.sendMessage(player, true, "joinsuccessfully");
        SimpleInfoHandler.broadcastMessage(this, true, false, "joinbroadcast",
                new StringPair("{player}", player.getName()),
                new StringPair("{playing}", String.valueOf(this.players.size())));

        if(!isSpectator)
            this.autoStart();

    }

    public void quit(Player player, boolean info) {
        UUID uuid = player.getUniqueId();
        if (!this.players.containsKey(uuid)) {
            SimpleInfoHandler.sendMessage(player, true, "notin");
        }
        this.players.remove(uuid);

        Scoreboard board = Bukkit.getScoreboardManager().getMainScoreboard();
        player.setScoreboard(board);

        PersistentInventory.clearInventory(player);
        PersistentInventory.loadInventory(player);

        player.setGameMode(GameMode.SURVIVAL);
        player.teleport(this.worldManager.hub);

        if (info) {
            SimpleInfoHandler.sendMessage(player, true, "quitsuccessfully");
            SimpleInfoHandler.broadcastMessage(this, true, false, "quitbroadcast",
                    new StringPair("{player}", player.getName()),
                    new StringPair("{playing}", String.valueOf(this.players.size())));
        }
    }

    public void autoStart() {
        if (this.downing != null) {
            return;
        }
        if (this.players.size() < this.min) {
            return;
        }
        this.downing = new BukkitRunnable() {
            int counter = 60;
            final List<Integer> points = Arrays.asList(60, 45, 30, 15, 10, 5, 4, 3, 2, 1);

            @Override
            public void run() {
                if (BasicGame.this.state != GameState.WAITING) {
                    this.cancel();
                    return;
                }
                if (BasicGame.this.players.size() < BasicGame.this.min) {
                    SimpleInfoHandler.broadcastMessage(BasicGame.this.game, true, false, "canceldowning");
                    this.cancel();
                    return;
                }
                if (this.counter <= 0) {
                    BasicGame.this.tryToStart();
                    this.cancel();
                    return;
                }
                if (BasicGame.this.players.size() >= 0.75d * BasicGame.this.max && this.counter > 15) {
                    SimpleInfoHandler.broadcastMessage(BasicGame.this.game, true, false, "quickdowning");
                    this.counter = 15;
                }
                if (this.points.contains(this.counter)) {
                    SimpleInfoHandler.broadcastMessage(BasicGame.this.game, true, false, "down", new StringPair("%time%", String.valueOf(this.counter)));
                }
                this.counter--;
            }
        }.runTaskTimer(FinalFight.plugin, 0L, 20L);
    }

    public String tryToStart() {
        if (this.state != GameState.WAITING) {
            return "notwaiting";
        }
        if (this.players.size() < this.min) {
            return "notenoughplayer";
        }
        this.state = GameState.RUNNING;
        this.init();
        return "startsuccessfully";
    }


    public void beforeInit() {

    }

    public void afterInit() {

    }

    public void beforeEnd() {

    }

    public void afterEnd() {

    }

    public void tick() {

    }

    public void init() {
        this.beforeInit();
        this.downing = null;

        for (UUID uuid : this.players.keySet()) {
            Player player = Bukkit.getPlayer(uuid);
            //TODO customized
            player.setHealth(player.getMaxHealth());
            player.setFoodLevel(20);
            for (PotionEffect effect : player.getActivePotionEffects()) {
                player.removePotionEffect(effect.getType());
            }

            Location loc = this.worldManager.getRandomSpawn();
            loc.getWorld().loadChunk(loc.getChunk());
            player.teleport(loc);
        }

        SimpleInfoHandler.broadcastTitle(this, false,
                "gamestart.title",
                "gamestart.subtitle");
        SimpleInfoHandler.broadcastMessage(this, true, false, "gamestart.message");

        this.afterInit();
        this.run();
    }

    public void run() {
        new BukkitRunnable() {
            @Override
            public void run() {
                tick();
                BasicGame.this.timeCounter++;
                if (BasicGame.this.timeCounter == 60) {
                    SimpleInfoHandler.broadcastMessage(BasicGame.this.game, true, false, "lessenstart");
                    SimpleInfoHandler.broadcastMessage(BasicGame.this.game, true, false, "pvpstart");
                    BasicGame.this.worldManager.startLessen();
                }
                if (BasicGame.this.getLiving() <= 1) {
                    Player winner = null;
                    for (UUID uuid : BasicGame.this.players.keySet()) {
                        Player player = Bukkit.getPlayer(uuid);
                        if (BasicGame.this.isAlive(player)) {
                            winner = player;
                        }
                    }
                    if (winner != null) {
                        SimpleInfoHandler.sendMessage(winner, true, "win");
                        StatManager.stats.get(winner.getUniqueId()).win();
                    }
                    SimpleInfoHandler.broadcastMessage(BasicGame.this.game, true, false, "gameend",
                            new StringPair("{player}", winner.getName()));

                    BasicGame.this.end();
                    this.cancel();
                }
            }
        }.runTaskTimer(FinalFight.plugin, 0L, 20L);
    }

    public void end() {
        this.beforeEnd();
        for (UUID uuid : ((HashMap<UUID, BasicGame>) this.players.clone()).keySet()) {
            Player player = Bukkit.getPlayer(uuid);
            PersistentInventory.clearInventory(player);
            PersistentInventory.loadInventory(player);
            this.quit(player, false);
        }
        this.state = GameState.REFRESHING;
        new BukkitRunnable() {
            @Override
            public void run() {
                BasicGame.this.state = GameState.WAITING;
            }
        }.runTaskLaterAsynchronously(FinalFight.plugin, 200L);
        this.clear();
        this.afterEnd();
    }

    public void clear() {
        this.players.clone();
        this.timeCounter = 0;
        this.worldManager.initWorldSettings();
    }

    public int getLiving() {
        int cnt = 0;
        for (UUID uuid : this.players.keySet()) {
            BasicGamer stat = this.players.get(uuid);
            if (stat.isAlive) {
                cnt++;
            }
        }
        return cnt;
    }

    public boolean isAlive(Player player) {
        return this.players.get(player.getUniqueId()).isAlive;
    }
}
